﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

using LanguageDetector.Data;

namespace LanguageDetector.Test
{
    [TestFixture]
    public class DB03_CharacterEncodingDB_CRUD : IDisposable
    {
        #region vars + setup/teardowns
        Random _rand = new Random();
        List<LanguageStat> _langs = new List<LanguageStat>();
        List<CharacterEncoding> _encs = new List<CharacterEncoding>();
        List<int> _langEncIDs = new List<int>();

        public DB03_CharacterEncodingDB_CRUD()
        {
            CreateTestData();
            Insert_LanguageStats();
            Insert_CharacterEncodings();
            Insert_LanguageEncodings();
        }

        void CreateTestData()
        {
            _langs.Add(new LanguageStat()
            {
                ISO2 = "98",
                IncludeASCII = true,
                Name = "888888",
                BiGramTotal = _rand.Next(10, int.MaxValue / 100),
            });
            _langs.Add(new LanguageStat()
            {
                ISO2 = "97",
                IncludeASCII = true,
                Name = "777777777777",
                BiGramTotal = _rand.Next(10, int.MaxValue / 100),
            });

            _encs.Add(new CharacterEncoding() { Encoding = "2222" });
            _encs.Add(new CharacterEncoding() { Encoding = "66666" });
        }

        void Insert_LanguageStats()
        {
            Assert.IsNotEmpty(_langs);
            LanguageStatDB.Save(_langs);
            _langs.ForEach(l => Assert.Greater(l.ID, 0));
        }

        void Insert_CharacterEncodings()
        {
            var langIDs = (from l in _langs select l.ID).ToList();
            var sb = new StringBuilder();
            _encs.ForEach(e =>
            {
                e.LanguageIDs.AddRange(langIDs);
                sb.AppendFormat("insert into character_encoding (name) values ('{0}');\r\n", e.Encoding);
                sb.Append("select last_insert_rowid() as lastid;\r\n");
            });
            var qe = new Query() { Text = sb.ToString() };
            var j = 0;
            var errors = qe.ExecuteReader(dr =>
            {
                _encs[j].ID = dr.GetInt32(0);
                j++;
            });
            Assert.IsEmpty(errors);
            _encs.ForEach(en => Assert.Greater(en.ID, 0));
        }

        void Insert_LanguageEncodings()
        {
            var sb = new StringBuilder();
            _encs.ForEach(e => _langs.ForEach(l =>
            {
                sb.AppendFormat("insert into language_encoding (language,encoding) values ({0},{1});\r\n", l.ID, e.ID);
                sb.Append("select last_insert_rowid() as lastid;\r\n");
            }));
            var qe = new Query() { Text = sb.ToString() };
            var errors = qe.ExecuteReader(dr => _langEncIDs.Add(dr.GetInt32(0)));
            Assert.IsEmpty(errors);
            _langEncIDs.ForEach(id => Assert.Greater(id, 0));
        }

        bool _disposed = false;
        public void Dispose()
        {
            lock (this)
            {
                if (!_disposed)
                {
                    _disposed = true;
                    var errors = new List<Exception>();
                    var vac = false;

                    if (!_langEncIDs.IsNullOrEmpty())
                    {
                        vac = true;
                        var sb = new StringBuilder("delete from language_encoding where id in (");
                        _langEncIDs.ForEach(id => sb.AppendFormat("{0},", id));
                        sb.Length--;
                        sb.Append(");");
                        var q = new Query() { Text=sb.ToString() };
                        errors.AddRange(q.ExecuteNoneReader());
                    }
                    var langs = (from l in _langs where l.ID > 0 select l.ID).ToList();
                    if (!langs.IsNullOrEmpty())
                    {
                        vac = true;
                        var sb = new StringBuilder("delete from language_stat where id in (");
                        langs.ForEach(id => sb.AppendFormat("{0},", id));
                        sb.Length--;
                        sb.Append(");");
                        var q = new Query() { Text = sb.ToString() };
                        errors.AddRange(q.ExecuteNoneReader());
                    }
                    var encs = (from e in _encs where e.ID > 0 select e.ID).ToList();
                    if (!encs.IsNullOrEmpty())
                    {
                        vac = true;
                        var sb = new StringBuilder("delete from character_encoding where id in (");
                        encs.ForEach(id => sb.AppendFormat("{0},", id));
                        sb.Length--;
                        sb.Append(");");
                        var q = new Query() { Text = sb.ToString() };
                        errors.AddRange(q.ExecuteNoneReader());
                    }
                    if (vac)
                    {
                        var q = new Query() { Text = "Vacuum;" };
                        errors.AddRange(q.ExecuteNoneReader());
                    }
                    Assert.IsEmpty(errors);
                }
            }
        }
        ~DB03_CharacterEncodingDB_CRUD()
        {
            Dispose();
        }
        #endregion

        [Test]
        public void T10_GetAll()
        {
            var res = CharacterEncodingDB.GetAll();
            Assert.IsNotNull(res);
            Assert.IsNotEmpty(res);
            Assert.IsEmpty(res.Errors);
            res.ForEach(re =>
            {
                Assert.Greater(re.ID, 0);
                Assert.IsNotEmpty(re.Encoding);
                Assert.IsNotNull(re.LanguageIDs);

                var og = (from o in _encs where o.ID == re.ID select o).FirstOrDefault();
                if (og != null)
                {
                    Assert.AreEqual(og.Encoding, re.Encoding);
                    Assert.AreEqual(og.LanguageIDs.Count, re.LanguageIDs.Count);
                    og.LanguageIDs.ForEach(oid => Assert.Contains(oid, re.LanguageIDs));
                }
            });
        }
    }
}
